/* libstdf -- library for reading writing and manipulating STDF files and data.
   Copyright (C) 2009 Tushar Jog
   
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 3 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General
   Public License along with this library; if not, write to the
   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301 USA 
*/

using System;
using System.Collections.Generic;
using System.IO;
using System.Diagnostics;

using stdf;

using U1 = System.Byte;
//using C1 = System.SByte;
using C1 = System.Char;
using B1 = System.Byte;
using N1 = System.Byte;
using I1 = System.SByte;

using U2 = System.UInt16;
using I2 = System.Int16;

using U4 = System.UInt32;
using I4 = System.Int32;
using R4 = System.Single;

using R8 = System.Double;

namespace stdf {

    public class Stream {

        public Stream( string name, RWMode mode) {
            init();
            streamName = name;
            rwMode     = mode;
        }
        public Stream() {
            init();
        }
        ~Stream() {}

        public void setByteOrder(ByteOrder order) {
            desiredByteOrder = order;
            if(desiredByteOrder != nativeByteOrder)
                swap = true;
        }

        private void init() {
            nativeByteOrder = Utility.getNativeByteOrder();
            desiredByteOrder = nativeByteOrder;
            swap = false;
            byteCount = 0;
            recStartCount = 0;
            recReadLengthMax = 0;
            recReadCount = 0;
            
        	this.recordTypeCount = new Dictionary<RecordType, uint>();
            recordTypeCount.Add( RecordType.FAR, 0);   
            recordTypeCount.Add( RecordType.ATR, 0);   
            recordTypeCount.Add( RecordType.MIR, 0);   
            recordTypeCount.Add( RecordType.MRR, 0);   
            recordTypeCount.Add( RecordType.PCR, 0);   
            recordTypeCount.Add( RecordType.HBR, 0);   
            recordTypeCount.Add( RecordType.SBR, 0);   
            recordTypeCount.Add( RecordType.PMR, 0);   
            recordTypeCount.Add( RecordType.PGR, 0);   
            recordTypeCount.Add( RecordType.PLR, 0);   
            recordTypeCount.Add( RecordType.RDR, 0);   
            recordTypeCount.Add( RecordType.SDR, 0);   
            recordTypeCount.Add( RecordType.WIR, 0);   
            recordTypeCount.Add( RecordType.WRR, 0);   
            recordTypeCount.Add( RecordType.WCR, 0);   
            recordTypeCount.Add( RecordType.PIR, 0);   
            recordTypeCount.Add( RecordType.PRR, 0);   
            recordTypeCount.Add( RecordType.TSR, 0);   
            recordTypeCount.Add( RecordType.PTR, 0);   
            recordTypeCount.Add( RecordType.MPR, 0);   
            recordTypeCount.Add( RecordType.FTR, 0);   
            recordTypeCount.Add( RecordType.BPS, 0);   
            recordTypeCount.Add( RecordType.EPS, 0);   
            recordTypeCount.Add( RecordType.GDR, 0);   
            recordTypeCount.Add( RecordType.DTR, 0);   
            recordTypeCount.Add( RecordType.Header, 0);   
            recordTypeCount.Add( RecordType.Reserved, 0);   
        }
        
        public bool open(string name, RWMode mode) {
            bool success = false;

            streamName = name;
            rwMode     = mode;

            if(mode == RWMode.ReadOnly) {
                // mode is ReadOnly, open file for reading and prohibit writing from now on
                filestream = File.OpenRead( streamName);
                // or
                //filestream = File.Open( streamName, FileMode.Open);
                if(filestream.CanRead == false) {
                    success = false;
                    rwMode = RWMode.None;
                    streamName = "";
                }
                else {
                    success = true;
                    reader = new BinaryReader( filestream, System.Text.Encoding.Default);
                }
            }
            else if(mode == RWMode.WriteOnly) {
                // RWMode is WriteOnly, open file for writing and prohibit reading from
                // now on
                // TODO: For now truncate file to zero if it already exists, later on
                //       Add code to append STDF data to file and update audit trails record.
                filestream.Close();
                filestream = File.OpenWrite( streamName);
                // or
                //filestream = File.Open( streamName, FileMode.Create);
                if(filestream.CanWrite == false) {
                    success = false;
                }
                else {
                    success = true;
                }
            }
            else {
                // will return success is false
            }

            return success;
        }

        public bool close() {
            if(rwMode == RWMode.ReadOnly)
                reader.Close();
            if(rwMode == RWMode.WriteOnly)
                writer.Close();
            return true;
        }

        public uint skip(U2 length) {
                uint readCount = 0;
                Debug.Assert(rwMode == RWMode.ReadOnly);
                try {
                        if(length > 0) {
                                byte[] buf = new Byte[length];
                                buf = reader.ReadBytes((int) length);
                        readCount = length;
                        }
                }
                catch(EndOfStreamException e) {
                Console.WriteLine("Error reading data: {0}.", e.GetType().Name);
            }

            byteCount    += readCount;
            recReadCount += readCount;

            return readCount;
        }

        //
        // Check to see if it is a open, readable, and if we can peek one char
        //
        public bool isReadable() {
            bool status = false;
            if(rwMode == RWMode.ReadOnly) {
                status = filestream.CanRead;
                
                try {
                	int lookAhead = reader.PeekChar();
                    if(lookAhead == -1)
                        status = false;
                }
                catch(IOException e) {
                    Console.WriteLine("Error reading data: {0}.", e.GetType().Name);
                    status = false;
                }
                catch(ArgumentException) {
                	Console.WriteLine( "some error occured");
                	status = false;
                }
                
            }

            return status;
        }
        
        public uint getRecordTypeCount(RecordType recType) {
                return recordTypeCount[recType];
        }
        
        //
        // Read operations
        //
        public int readRecordHeader(ref RecordHeader rh) {
                beginRecord(4);
                
                read(ref rh.length);
                read(ref rh.type);
                read(ref rh.subType);
                
                currRecordHeader = rh;
                
                return endRecord();
        }
        
        public int readRecord(ref FARRecord rec, uint len) {
                beginRecord(len);
                read(ref rec.cpuType);
                read(ref rec.stdfVersion);
                
                recordTypeCount[RecordType.FAR] = recordTypeCount[RecordType.FAR] + 1;
                
                return endRecord();
        }
        public int readRecord(ref FARRecord rec) {
                beginRecord(0);
                read(ref rec.cpuType);
                read(ref rec.stdfVersion);
                
                recordTypeCount[RecordType.FAR] = recordTypeCount[RecordType.FAR] + 1;
                
                return endRecord();
        }
        
        public int readRecord(ref ATRRecord rec, uint len) {
                beginRecord(len);
                read(ref rec.modificationTime);
                read(ref rec.commandLine);
                recordTypeCount[RecordType.ATR] = recordTypeCount[RecordType.ATR] + 1;
                return endRecord();
        }
        public int readRecord(ref ATRRecord rec) {
                beginRecord(0);
                read(ref rec.modificationTime);
                read(ref rec.commandLine);
                recordTypeCount[RecordType.ATR] = recordTypeCount[RecordType.ATR] + 1;
                return endRecord();
        }
        
        public int readRecord(ref MIRRecord rec, uint len) {
                beginRecord(len);
                
                read(ref rec.setupTime);
                read(ref rec.startTime);
                read(ref rec.stationNumber);
                read(ref rec.modeCode);
                read(ref rec.retestCode);
                read(ref rec.protectionCode);
                read(ref rec.burninTime);
                read(ref rec.commandModeCode);
                read(ref rec.lotID);
                read(ref rec.partType);
                read(ref rec.nodeName);
                read(ref rec.testerType);
                read(ref rec.jobName);
                read(ref rec.jobRevision);
                read(ref rec.sublotID);
                read(ref rec.operatorName);
                read(ref rec.executiveType);
                read(ref rec.executiveVersion);
                read(ref rec.testCode);
                read(ref rec.testTemp);
                read(ref rec.userText);
                read(ref rec.auxFile);
                read(ref rec.packageType);
                read(ref rec.familyID);
                read(ref rec.dateCode);
                read(ref rec.facilityID);
                read(ref rec.floorID);
                read(ref rec.processID);
                read(ref rec.operatorFrequency);
                read(ref rec.specName);
                read(ref rec.specVersion);
                read(ref rec.flowID);
                read(ref rec.setupID);
                read(ref rec.designRevision);
                read(ref rec.engineeringLotID);
                read(ref rec.romCode);
                read(ref rec.serialNumber);
                read(ref rec.supervisorName);
                recordTypeCount[RecordType.MIR] = recordTypeCount[RecordType.MIR] + 1;

                return endRecord();
        }

public int readRecord(ref SDRRecord rec, uint len) {
    beginRecord(len);

    read(ref rec.headNumber);
    read(ref rec.siteGroup);
    read(ref rec.siteCount);
    for(uint i=0; i < rec.siteCount; i++) {
        U1 siteNum = 0;
        read(ref siteNum);
        rec.siteNumbers.Add(siteNum);
    }
    read(ref rec.handlerType);
    read(ref rec.handlerID);
    read(ref rec.probeCardType);
    read(ref rec.probeCardID);
    read(ref rec.loadBoardType);
    read(ref rec.loadBoardID);
    read(ref rec.dibType);
    read(ref rec.dibID);
    read(ref rec.cableType);
    read(ref rec.cableID);
    read(ref rec.contactorType);
    read(ref rec.contactorID);
    read(ref rec.laserType);
    read(ref rec.laserID);
    read(ref rec.extraType);
    read(ref rec.extraID);
    recordTypeCount[RecordType.SDR] = recordTypeCount[RecordType.SDR] + 1;

    return endRecord();
}

public int readRecord(ref PMRRecord rec, uint len) {
    beginRecord(len);

    read(ref rec.pmrIndex);
    read(ref rec.channelType);
    read(ref rec.channelName);
    read(ref rec.physicalName);
    read(ref rec.logicalName);
    read(ref rec.headNumber);
    read(ref rec.siteNumber);
    recordTypeCount[RecordType.PMR] = recordTypeCount[RecordType.PMR] + 1;

    return endRecord();
}

public int readRecord(ref PGRRecord rec, uint len) {
    beginRecord(len);

    read(ref rec.groupIndex);
    read(ref rec.groupName);
    read(ref rec.indexCount);
    for(uint i=0; i < rec.indexCount; i++) {
        U2 index = 0;
        read(ref index);
        rec.pmrIndex.Add(index);
    }
    recordTypeCount[RecordType.PGR] = recordTypeCount[RecordType.PGR] + 1;

    return endRecord();
}

public int readRecord(ref PIRRecord rec, uint len) {
    beginRecord(len);

    read(ref rec.headNumber);
    read(ref rec.siteNumber);
    recordTypeCount[RecordType.PIR] = recordTypeCount[RecordType.PIR] + 1;

    return endRecord();
}

public int readRecord(ref PLRRecord rec, uint len) {
    beginRecord(len);

    read(ref rec.groupCount);
    for(uint i=0; i < rec.groupCount; i++) {
        U2 index = 0;
        read(ref index);
        rec.groupIndex.Add(index);
    }
    for(uint i=0; i < rec.groupCount; i++) {
        U2 mode = 0;
        read(ref mode);
        rec.groupMode.Add(mode);
    }
    for(uint i=0; i < rec.groupCount; i++) {
        U1 radix = 0;
        read(ref radix);
        rec.groupRadix.Add(radix);
    }
    for(uint i=0; i < rec.groupCount; i++) {
    	CN charRight = new CN();
        read(ref charRight);
        rec.programCharRight.Add(charRight);
    }
    for(uint i=0; i < rec.groupCount; i++) {
    	CN charRight = new CN();
        read(ref charRight);
        rec.returnCharRight.Add(charRight);
        //rec.returnCharRight.Add(charRight);
    }
    for(uint i=0; i < rec.groupCount; i++) {
    	CN charLeft = new CN();
        read(ref charLeft);
        rec.programCharLeft.Add(charLeft);
    }
    for(uint i=0; i < rec.groupCount; i++) {
    	CN charLeft = new CN();
        read(ref charLeft);
        rec.returnCharLeft.Add(charLeft);
    }
    recordTypeCount[RecordType.PLR] = recordTypeCount[RecordType.PLR] + 1;

    return endRecord();
}

public int readRecord(ref PTRRecord rec, uint len) {
    beginRecord(len);

    read(ref rec.testNumber);
    read(ref rec.headNumber);
    read(ref rec.siteNumber);
    read(ref rec.testFlag);
    read(ref rec.parmFlag);
    read(ref rec.testResult);
    read(ref rec.testText);
    read(ref rec.alarmID);
    read(ref rec.optFlag);
    if(rec.optFlag != 0xFF) {
    	if(rec.isResultScaleInValid())
    		skip(1);
    	else
        	read(ref rec.resultScale);
        read(ref rec.llmScale);
        read(ref rec.hlmScale);
        read(ref rec.loLimit);
        read(ref rec.hiLimit);
        read(ref rec.units);
        read(ref rec.cResFmt);
        read(ref rec.cLlmFmt);
        read(ref rec.cHlmFmt);
        read(ref rec.loSpec);
        read(ref rec.hiSpec);
    }
    recordTypeCount[RecordType.PTR] = recordTypeCount[RecordType.PTR] + 1;

    return endRecord();
}

public int readRecord(ref FTRRecord rec, uint len)
{
    beginRecord(len);

    read(ref rec.testNumber);
    read(ref rec.headNumber);
    read(ref rec.siteNumber);
    read(ref rec.testFlag);
    read(ref rec.optFlag);

    read( ref rec.cycleCount);
    read( ref rec.relativeVectorAddress);
    read( ref rec.repeatCount);
    read( ref rec.numFail);
    read( ref rec.xFailAddress);
    read( ref rec.yFailAddress);
    read( ref rec.vectorOffset);

    read( ref rec.returnIcnt);
    read( ref rec.programmedIcnt);

    rec.returnIndexes.Clear();
    rec.returnStates.Clear();
    if (rec.returnIcnt > 0)
    {
        for (uint i = 0; i < rec.returnIcnt; i++)
        {
            U2 index = 0;
            read(ref index);
            rec.returnIndexes.Add(index);
        }
        for (U2 j = 1; j <= ((rec.returnIcnt+1)/2); j++)
        {
            N1 state = 0;
            read(ref state);
            rec.returnStates.Add( (N1) (state & 0x0F));
            if (2 * j <= rec.returnIcnt)
                rec.returnStates.Add((N1)((state & 0xF0) >> 4));
        }
    }

    rec.programmedIndexes.Clear();
    rec.programmedStates.Clear();
    if (rec.programmedIcnt > 0)
    {
        for (uint i = 0; i < rec.programmedIcnt; i++)
        {
            U2 index = 0;
            read(ref index);
            rec.programmedIndexes.Add(index);
        }
        for (U2 j = 1; j <= ((rec.programmedIcnt + 1) / 2); j++)
        {
            N1 state = 0;
            read(ref state);
            rec.programmedStates.Add((N1)(state & 0x0F));
            if (2 * j <= rec.programmedIcnt)
                rec.programmedStates.Add((N1)((state & 0xF0) >> 4));
        }
    }

    read( ref rec.failPin);
    read( ref rec.vectorName);
    read( ref rec.timeSet);
    read( ref rec.opCode);
    read( ref rec.testText);
    read( ref rec.alarmID);
    read( ref rec.programmedText);
    read( ref rec.resultText);
    read( ref rec.patternGeneratorNumber);
    read( ref rec.spinMap);

    recordTypeCount[RecordType.FTR] = recordTypeCount[RecordType.FTR] + 1;

    return endRecord();
}

public int readRecord(ref PRRRecord rec, uint len) {
    beginRecord(len);

    read(ref rec.headNumber);
    read(ref rec.siteNumber);
    read(ref rec.partFlag);
    read(ref rec.numTests);
    read(ref rec.hardBin);
    read(ref rec.softBin);
    read(ref rec.xCoord);
    read(ref rec.yCoord);
    read(ref rec.testTime);
    read(ref rec.partID);
    read(ref rec.partText);
    read(ref rec.partFix);
    recordTypeCount[RecordType.PRR] = recordTypeCount[RecordType.PRR] + 1;

    return endRecord();
}

int readRecord(ref TSRRecord rec, uint len) {
    beginRecord(len);

    read(ref rec.headNumber);
    read(ref rec.siteNumber);
    read(ref rec.testType);
    read(ref rec.testNumber);
    read(ref rec.execCount);
    read(ref rec.failCount);
    read(ref rec.alarmCount);
    read(ref rec.testName);
    read(ref rec.sequencerName);
    read(ref rec.testLabel);
    read(ref rec.optFlag);
    read(ref rec.testTime);
    read(ref rec.testMin);
    read(ref rec.testMax);
    read(ref rec.testSums);
    read(ref rec.testSquares);
    recordTypeCount[RecordType.TSR] = recordTypeCount[RecordType.TSR] + 1;

    return endRecord();
}

public int readRecord(ref WCRRecord rec, uint len) {
    beginRecord(len);

    read(ref rec.waferSize);
    read(ref rec.dieHeight);
    read(ref rec.dieWidth);
    read(ref rec.waferUnits);
    read(ref rec.waferFlat);
    read(ref rec.centerX);
    read(ref rec.centerY);
    read(ref rec.positiveX);
    read(ref rec.positiveY);
    recordTypeCount[RecordType.WCR] = recordTypeCount[RecordType.WCR] + 1;

    return endRecord();
}

public int readRecord(ref WIRRecord rec, uint len) {
    beginRecord(len);

    read(ref rec.headNumber);
    read(ref rec.siteGroup);
    read(ref rec.startTime);
    read(ref rec.waferID);
    recordTypeCount[RecordType.WIR] = recordTypeCount[RecordType.WIR] + 1;

    return endRecord();
}

public int readRecord(ref WRRRecord rec, uint len) {
    beginRecord(len);

    read(ref rec.headNumber);
    read(ref rec.siteGroup);
    read(ref rec.finishTime);
    read(ref rec.partCount);
    read(ref rec.retestCount);
    read(ref rec.abortCount);
    read(ref rec.goodCount);
    read(ref rec.funcCount);
    read(ref rec.waferID);
    read(ref rec.fabWaferID);
    read(ref rec.waferFrameID);
    read(ref rec.waferMaskID);
    read(ref rec.userDescription);
    read(ref rec.execDescription);
    recordTypeCount[RecordType.WRR] = recordTypeCount[RecordType.WRR] + 1;

    return endRecord();
}

public int readRecord(ref HBRRecord rec, uint len) {
    beginRecord(len);

    read(ref rec.headNumber);
    read(ref rec.siteNumber);
    read(ref rec.hbinNumber);
    read(ref rec.hbinCount);
    read(ref rec.hbinPF);
    read(ref rec.hbinName);
    recordTypeCount[RecordType.HBR] = recordTypeCount[RecordType.HBR] + 1;

    return endRecord();
}

public int readRecord(ref SBRRecord rec, uint len) {
    beginRecord(len);

    read(ref rec.headNumber);
    read(ref rec.siteNumber);
    read(ref rec.sbinNumber);
    read(ref rec.sbinCount);
    read(ref rec.sbinPF);
    read(ref rec.sbinName);
    recordTypeCount[RecordType.SBR] = recordTypeCount[RecordType.SBR] + 1;

    return endRecord();
}

public int readRecord(ref PCRRecord rec, uint len) {
    beginRecord(len);

    read(ref rec.headNumber);
    read(ref rec.siteNumber);
    read(ref rec.partCount);
    read(ref rec.retestCount);
    read(ref rec.abortCount);
    read(ref rec.goodCount);
    read(ref rec.funcCount);
    recordTypeCount[RecordType.PCR] = recordTypeCount[RecordType.PCR] + 1;

    return endRecord();
}

public int readRecord(ref MRRRecord rec, uint len) {
    beginRecord(len);

    read(ref rec.finishTime);
    read(ref rec.dispositionCode);
    read(ref rec.userLotDescription);
    read(ref rec.executiveLotDescription);

    recordTypeCount[RecordType.MRR] = recordTypeCount[RecordType.MRR] + 1;

    return endRecord();
}
        

        // 
        // Primitive operations
        // 
        protected uint read(ref U1 val) {
            uint readCount = 0;
            Debug.Assert(rwMode == RWMode.ReadOnly);
            if(recReadCount >= recReadLengthMax)
                return 0;

            try {
                val = reader.ReadByte();
                readCount = 1;
            }
            catch(EndOfStreamException e) {
                Console.WriteLine("Error reading data: {0}.", e.GetType().Name);
            }

            byteCount    += readCount;
            recReadCount += readCount;

            return readCount;
        }

        protected uint read(ref C1 val) {
            uint readCount = 0;
            Debug.Assert(rwMode == RWMode.ReadOnly);
            if(recReadCount >= recReadLengthMax)
                return 0;

            try {
                val = (C1) reader.ReadByte();
                readCount = 1;
            }
            catch(EndOfStreamException e) {
                Console.WriteLine("Error reading data: {0}.", e.GetType().Name);
            }

            byteCount    += readCount;
            recReadCount += readCount;

            return readCount;
        }

        protected uint read(ref I1 val) {
            uint readCount = 0;
            Debug.Assert(rwMode == RWMode.ReadOnly);
            if(recReadCount >= recReadLengthMax)
                return 0;

            try {
            	//byte temp = 0;
            	//temp = reader.ReadByte();
            	//val = (I1) temp;
            	val = reader.ReadSByte();
                //val = (I1) reader.ReadByte();
                readCount = 1;
            }
            catch(System.IO.EndOfStreamException e) {
                Console.WriteLine("Error reading data: {0}.", e.GetType().Name);
            }
            /*
            catch(System.IO.IOException e) {
                Console.WriteLine("Error reading data: {0}.", e.GetType().Name);
            }
            catch(System.ObjectDisposedException e) {
                Console.WriteLine("Error reading data: {0}.", e.GetType().Name);
            }
                        
            catch(System.OverflowException e) {
                Console.WriteLine("Error reading data: {0}.", e.GetType().Name);
            }
            */

            byteCount    += readCount;
            recReadCount += readCount;

            return readCount;
        }

        protected uint read(ref U2 val) {
            uint readCount = 0;
            Debug.Assert(rwMode == RWMode.ReadOnly);
            if(recReadCount >= recReadLengthMax)
                return 0;

            try {
                const uint size = 2;
                byte[] buf = reader.ReadBytes((int) size);
                //Utility.translate( buf, val, swap);
                val = Utility.translateToU2( buf, swap);
                readCount = size;
            }
            catch(EndOfStreamException e) {
                Console.WriteLine("Error reading data: {0}.", e.GetType().Name);
            }

            byteCount    += readCount;
            recReadCount += readCount;

            return readCount;
        }

        protected uint read(ref I2 val) {
            uint readCount = 0;
            Debug.Assert(rwMode == RWMode.ReadOnly);
            if(recReadCount >= recReadLengthMax)
                return 0;

            try {
                const uint size = 2;
                byte[] buf = reader.ReadBytes((int) size);
                //Utility.translate( buf, val, swap);
                val = Utility.translateToI2( buf, swap);
                readCount = size;
            }
            catch(EndOfStreamException e) {
                Console.WriteLine("Error reading data: {0}.", e.GetType().Name);
            }

            byteCount    += readCount;
            recReadCount += readCount;

            return readCount;
        }

        protected uint read(ref U4 val) {
            uint readCount = 0;
            Debug.Assert(rwMode == RWMode.ReadOnly);
            if(recReadCount >= recReadLengthMax)
                return 0;

            try {
                const uint size = 4;
                byte[] buf = reader.ReadBytes((int) size);
                //Utility.translate( buf, val, swap);
                val = Utility.translateToU4( buf, swap);
                readCount = size;
            }
            catch(EndOfStreamException e) {
                Console.WriteLine("Error reading data: {0}.", e.GetType().Name);
            }

            byteCount    += readCount;
            recReadCount += readCount;

            return readCount;
        }

        protected uint read(ref I4 val) {
            uint readCount = 0;
            Debug.Assert(rwMode == RWMode.ReadOnly);
            if(recReadCount >= recReadLengthMax)
                return 0;

            try {
                const uint size = 4;
                byte[] buf = reader.ReadBytes((int) size);
                //Utility.translate( buf, val, swap);
                val = Utility.translateToI4( buf, swap);
                readCount = size;
            }
            catch(EndOfStreamException e) {
                Console.WriteLine("Error reading data: {0}.", e.GetType().Name);
            }

            byteCount    += readCount;
            recReadCount += readCount;

            return readCount;
        }

        protected uint read(ref R4 val) {
            uint readCount = 0;
            Debug.Assert(rwMode == RWMode.ReadOnly);
            if(recReadCount >= recReadLengthMax)
                return 0;

            try {
                const uint size = 4;
                byte[] buf = reader.ReadBytes((int) size);
                //Utility.translate( buf, val, swap);
                val = Utility.translateToR4( buf, swap);
                readCount = size;
            }
            catch(EndOfStreamException e) {
                Console.WriteLine("Error reading data: {0}.", e.GetType().Name);
            }

            byteCount    += readCount;
            recReadCount += readCount;

            return readCount;
        }

        protected uint read(ref R8 val) {
            uint readCount = 0;
            Debug.Assert(rwMode == RWMode.ReadOnly);
            if(recReadCount >= recReadLengthMax)
                return 0;

            try {
                const uint size = 8;
                byte[] buf = reader.ReadBytes((int) size);
                //Utility.translate( buf, val, swap);
                val = Utility.translateToR8( buf, swap);
                readCount = size;
            }
            catch(EndOfStreamException e) {
                Console.WriteLine("Error reading data: {0}.", e.GetType().Name);
            }

            byteCount    += readCount;
            recReadCount += readCount;

            return readCount;
        }

        protected uint read(ref CN val) {
            uint readCount = 0;
            Debug.Assert(rwMode == RWMode.ReadOnly);
            if(recReadCount >= recReadLengthMax)
                return 0;

            try {
                byte len = reader.ReadByte();
                if(len > 0) {
                    byte[] buf = reader.ReadBytes((int) len);
                    string temp = System.Text.ASCIIEncoding.ASCII.GetString(buf);
                    val.set(temp);
                }
                readCount = ((uint) len) + 1;
            }
            catch(EndOfStreamException e) {
                Console.WriteLine("Error reading data: {0}.", e.GetType().Name);
            }

            byteCount    += readCount;
            recReadCount += readCount;

            return readCount;
        }

        protected uint read(ref BN val) {
            uint readCount = 0;
            Debug.Assert(rwMode == RWMode.ReadOnly);
            if(recReadCount >= recReadLengthMax)
                return 0;

            try {
                byte len = reader.ReadByte();
                if(len > 0) {
                    byte[] buf = reader.ReadBytes((int) len);
                    List<U1> temp = new List<U1>();
                    for(uint i =0; i < buf.Length; i++)
                        temp.Add((U1) buf[i]);
                    val.set(ref temp);
                }
                readCount = ((uint) len) + 1;
            }
            catch(EndOfStreamException e) {
                Console.WriteLine("Error reading data: {0}.", e.GetType().Name);
            }

            byteCount    += readCount;
            recReadCount += readCount;

            return readCount;
        }

        protected uint read(ref DN val)
        {
            uint readCount = 0;
            Debug.Assert(rwMode == RWMode.ReadOnly);
            if (recReadCount >= recReadLengthMax)
                return 0;

            try
            {

                U2 len = 0;
                byte[] buflen = reader.ReadBytes(2);
                len = Utility.translateToU2(buflen, swap);

                int numBytes = (len / 8) + 1;
                if ((len % 8) == 0) numBytes--;

                if (len > 0)
                {
                    byte[] buf = reader.ReadBytes((int) numBytes);
                    List<U1> temp = new List<U1>();
                    for (uint i = 0; i < buf.Length; i++)
                        temp.Add((U1)buf[i]);
                    val.set(ref temp);
                }
                readCount = ((uint) numBytes) + 2;
            }
            catch (EndOfStreamException e)
            {
                Console.WriteLine("Error reading data: {0}.", e.GetType().Name);
            }

            byteCount    += readCount;
            recReadCount += readCount;

            return readCount;
        }
        private void beginRecord(uint len) {
                recStartCount = byteCount;
                
                if(len == 0)
                        recReadLengthMax = currRecordHeader.length;
                else
                        recReadLengthMax = len;
                recReadCount = 0;
        }

        private int endRecord() {
            return ((int) (byteCount - recStartCount));
        }

        private string                      streamName;
        private RWMode                      rwMode;
        private ByteOrder                   desiredByteOrder;
        private ByteOrder                   nativeByteOrder;
        private bool                        swap;

        private FileStream                  filestream;
        private BufferedStream              bufFilestream;

        private BinaryReader                reader;
        private BinaryWriter                writer;
        private ulong                       byteCount;
        private ulong                       recStartCount;
        private uint                        recReadLengthMax;
        private uint                        recReadCount;
        private RecordHeader                currRecordHeader;
        private Dictionary<RecordType,uint> recordTypeCount;
    };    


}
